﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Xml;
using ChinaClipping.ClippingMaster.Controls;
using ChinaClipping.ClippingMaster.Model;
using Clipping.Infrastructure.Models;
using System.Threading;
using System.Text.RegularExpressions;
using System.IO;

namespace ChinaClipping.ClippingMaster.Editor
{
    public partial class MultiClippingEditor : Form
    {
		//private static Encoding _xmlFileEncoding = Encoding.Unicode;
		//private static string XMLTEMPLATE = "<?xml version=\"1.0\" encoding=\"Unicode\"?><Clipping><ContentHtml /><ContentTxt /><Pictures /><CapPictures /></Clipping>";
		private static Encoding _xmlFileEncoding = Encoding.UTF8;
		private static string XMLTEMPLATE = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Clipping><ContentHtml /><ContentTxt /><Pictures /><CapPictures /></Clipping>";

        private HttpInfo _http;
        private User _currentuser;
        private List<News> _news;
        private ClientInfo _selectedclient;
        private List<ClassInfo> _selectedclass;
        private Dictionary<string, ClippingProperty> _controllist = new Dictionary<string, ClippingProperty>();
        private bool _fullchannel = false;//值为true时，提取频道形如 首页>资讯中心，否则形如： 资讯中心

		static MultiClippingEditor()
		{
			_xmlFileEncoding = Encoding.GetEncoding(Properties.Settings.Default.ClippingEncoding);
            initXmlTemplate();
		}

        private static void initXmlTemplate()
        {
            if (_xmlFileEncoding == Encoding.Unicode)
            {
                XMLTEMPLATE = "<?xml version=\"1.0\" encoding=\"Unicode\"?><Clipping><ContentHtml /><ContentTxt /><Pictures /><CapPictures /></Clipping>";
            }
            else if (_xmlFileEncoding == Encoding.UTF8)
            {
                XMLTEMPLATE = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Clipping><ContentHtml /><ContentTxt /><Pictures /><CapPictures /></Clipping>";
            }
            else
            {
                XMLTEMPLATE = string.Format("<?xml version=\"1.0\" encoding=\"{0}\"?><Clipping><ContentHtml /><ContentTxt /><Pictures /><CapPictures /></Clipping>", _xmlFileEncoding.WebName);
            }
        }

		
		public MultiClippingEditor(List<News> news, User user, HttpInfo httpInfo)
        {
            InitializeComponent();
            this._news = news;
            this._currentuser = user;
            this._http = httpInfo;
            showNews(news);
            getNewsContent(news);
            LoadSharedPropertiesControl();
        }

        private void getNewsContent(List<News> news)
        {
            WaitCallback wc = new WaitCallback(getNewsContent);
            foreach (var n in news)
            {
                ThreadPool.QueueUserWorkItem(wc, n);
            }
        }
        private void getNewsContent(object newsObj)
        {
            News news = newsObj as News;
            if (Uri.IsWellFormedUriString(news.Url, UriKind.Absolute))
            {
                Uri uri = new Uri(news.Url);
                string channel;
                string content = MyTools.NewsParser.GetContentContinuously(uri, out channel);
                news.Content = content;
                if (!string.IsNullOrEmpty(channel) && !_fullchannel)
                {
                    int index = channel.LastIndexOf(">");
                    if (index > 0 && index < channel.Length - 1)
                    {
                        channel = channel.Substring(index + 1);
                        channel = channel.Trim();
                    }
                }
                news.Channel = channel;
                this.Invoke(new Action<News>(setNewsReady), news);

            }
        }
        private void setNewsReady(News news)
        {
            news.IsReady = true;
            foreach (ListViewItem lvi in this.listView_News.Items)
            {
                if (lvi.Tag == news)
                {
                    lvi.SubItems[lvi.SubItems.Count - 1].Text = "Ready";
                    break;
                }
            }
        }

        private XmlDataDocument GenerateClipping(News news)
        {
            XmlDataDocument xmldoc = new XmlDataDocument();
            xmldoc.LoadXml(XMLTEMPLATE);
            XmlElement xe;
            XmlNode rootnode = xmldoc.SelectSingleNode("/Clipping");
            xe = rootnode as XmlElement;
            xe.SetAttribute("ClientId", this._selectedclient.Id);


            addClassNode(xmldoc, rootnode);//添加分类节点

            addLinkNode(news, xmldoc, rootnode);//添加链接节点


            addTitleNode(news, xmldoc, rootnode);
            addSummaryNode(news, xmldoc, rootnode);

            ClippingProperty cp;
            foreach (Control c in tableLayoutPanel1.Controls)
            {
                cp = c as ClippingProperty;
                if (cp != null)
                {



                    xe = xmldoc.CreateNode(XmlNodeType.Element, "Field", "") as XmlElement;
                    xe.SetAttribute("Name", cp.PropertyName);

                    string pValue = "";
                    switch (cp.PropertyName)
                    {
                        case "headlineC"://标题
                            pValue = news.Title;
                            break;
                        case "synopsisC": //摘要
                            pValue = news.Summary;
                            break;
                        case "mediaID"://媒体
                            pValue = news.Media;
                            break;
                        case "mediaDate"://日期
                            pValue = news.PubDate;
                            break;
                        case "Section": //版面
                            pValue = news.Channel;
                            break;
                        case "Words"://字数
                            pValue = ChinaClipping.ClippingMaster.MyTools.NewsParser.CountWords(news.Content).ToString();
                            break;
                        default:
                            pValue = cp.PropertyValue;
                            break;

                    }
                    xe.SetAttribute("Value", pValue);



                    rootnode.AppendChild(xe);


                }
            }
            foreach (Control c in this.flowLayoutPanel_PublicFields.Controls)
            {
                cp = c as ClippingProperty;
                if (cp != null)
                {
                    if (cp.Type == PropertyType.Field)
                    {
                        xe = xmldoc.CreateNode(XmlNodeType.Element, "Field", "") as XmlElement;
                        xe.SetAttribute("Name", cp.PropertyName);
                        string pValue = "";
                        switch (cp.PropertyName)
                        {
                            case "headlineC"://标题
                                pValue = news.Title;
                                break;
                            case "synopsisC": //摘要
                                pValue = news.Summary;
                                break;
                            case "mediaID"://媒体
                                pValue = news.Media;
                                break;
                            case "mediaDate"://日期
                                pValue = news.PubDate;
                                break;
                            case "Section": //版面
                                pValue = news.Channel;
                                break;
                            case "Words"://字数
                                pValue = ChinaClipping.ClippingMaster.MyTools.NewsParser.CountWords(news.Content).ToString();
                                break;
                            default:
                                pValue = cp.PropertyValue;
                                break;

                        }
                        xe.SetAttribute("Value", pValue);
                    }
                    else if (cp.Type == PropertyType.Property)
                    {
                        xe = xmldoc.CreateNode(XmlNodeType.Element, "Property", "") as XmlElement;
                        xe.SetAttribute("Name", cp.PropertyName);
                        string pValue = "";
                        switch (cp.PropertyName)
                        {
                            case "headlineC"://标题
                                pValue = news.Title;
                                break;
                            case "synopsisC": //摘要
                                pValue = news.Summary;
                                break;
                            case "mediaID"://媒体
                                pValue = news.Media;
                                break;
                            case "mediaDate"://日期
                                pValue = news.PubDate;
                                break;
                            case "Section": //版面
                                pValue = news.Channel;
                                break;
                            case "Words"://字数
                                pValue = ChinaClipping.ClippingMaster.MyTools.NewsParser.CountWords(news.Content).ToString();
                                break;
                            default:
                                pValue = cp.PropertyValue;
                                break;

                        }
                        xe.SetAttribute("Value", pValue);
                    }

                    rootnode.AppendChild(xe);

                }
            }

            xe = xmldoc.CreateNode(XmlNodeType.Element, "Field", "") as XmlElement;
            xe.SetAttribute("Name", "addedBy");
            xe.SetAttribute("Value", _currentuser.Id);
            rootnode.AppendChild(xe);

            foreach (Control c in this.flowLayoutPanel_ProfileFields.Controls)
            {
                cp = c as ClippingProperty;
                if (cp != null)
                {
                    if (cp.Type == PropertyType.Field)
                    {
                        xe = xmldoc.CreateNode(XmlNodeType.Element, "Field", "") as XmlElement;
                        xe.SetAttribute("Name", cp.PropertyName);
                        xe.SetAttribute("Value", cp.PropertyValue);
                    }
                    else
                    {
                        xe = xmldoc.CreateNode(XmlNodeType.Element, "Property", "") as XmlElement;
                        xe.SetAttribute("Name", cp.PropertyName);
                        xe.SetAttribute("Value", cp.PropertyValue);
                    }
                    rootnode.AppendChild(xe);
                }
            }
            foreach (Control c in this.flowLayoutPanel_MultiSelectProperty.Controls)
            {
                cp = c as ClippingProperty;
                if (cp != null)
                {
                    if (cp.Type == PropertyType.Field)
                    {
                        xe = xmldoc.CreateNode(XmlNodeType.Element, "Field", "") as XmlElement;
                        xe.SetAttribute("Name", cp.PropertyName);
                        xe.SetAttribute("Value", cp.PropertyValue);
                    }
                    else
                    {
                        xe = xmldoc.CreateNode(XmlNodeType.Element, "Property", "") as XmlElement;
                        xe.SetAttribute("Name", cp.PropertyName);
                        xe.SetAttribute("Value", cp.PropertyValue);
                    }
                    rootnode.AppendChild(xe);
                }
            }

            string html = news.Content;
            if (html == null)
                html = "";
            string txt = "";
            if (!string.IsNullOrEmpty(html))
            {
                HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
                doc.LoadHtml(html);
                txt = doc.DocumentNode.InnerText;
            }


            XmlCDataSection cdata = xmldoc.CreateCDataSection(html);
            xmldoc.SelectSingleNode("/Clipping/ContentHtml").AppendChild(cdata);
            cdata = xmldoc.CreateCDataSection(txt);
            xmldoc.SelectSingleNode("/Clipping/ContentTxt").AppendChild(cdata);
            foreach (Match m in Regex.Matches(html, "<img\\s+[^>]*?src=[\"\']?([^\">]+)[\"\']?[^>]*>", RegexOptions.IgnoreCase))
            {
                try
                {

                    string picbase64 = getBase64Pic(m.Groups[1].Value, news.Url);
                    xe = xmldoc.CreateNode(XmlNodeType.Element, "Pic", "") as XmlElement;
                    XmlCDataSection picdata = xmldoc.CreateCDataSection(picbase64);
                    xe.SetAttribute("url", m.Groups[1].Value);
                    xe.AppendChild(picdata);
                    xmldoc.SelectSingleNode("/Clipping/Pictures").AppendChild(xe);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }

            return xmldoc;
        }

        private void addSummaryNode(News news, XmlDataDocument xmldoc, XmlNode rootnode)
        {
            XmlElement xe = xmldoc.CreateNode(XmlNodeType.Element, "Field", "") as XmlElement;
            xe.SetAttribute("Name", "synopsisC");
            xe.SetAttribute("Value", news.Summary);
            rootnode.AppendChild(xe);
        }

        private void addTitleNode(News news, XmlDataDocument xmldoc, XmlNode rootnode)
        {

            XmlElement xe = xmldoc.CreateNode(XmlNodeType.Element, "Field", "") as XmlElement;
            xe.SetAttribute("Name", "headlineC");
            xe.SetAttribute("Value", news.Title);
            rootnode.AppendChild(xe);
        }

        private void addClassNode(XmlDataDocument xmldoc, XmlNode rootnode)
        {
            XmlElement xe = xmldoc.CreateNode(XmlNodeType.Element, "Classes", "") as XmlElement;
            foreach (ClassInfo ci in this._selectedclass)
            {
                XmlNode subNode = xmldoc.CreateNode(XmlNodeType.Element, "Class", "");
                XmlNode valueNode = xmldoc.CreateNode(XmlNodeType.Text, "ValueClass", "");
                valueNode.Value = ci.Id;
                subNode.AppendChild(valueNode);
                xe.AppendChild(subNode);

            }
            rootnode.AppendChild(xe);
        }

        private static void addLinkNode(News news, XmlDataDocument xmldoc, XmlNode rootnode)
        {
            XmlElement xe = xmldoc.CreateNode(XmlNodeType.Element, "Links", "") as XmlElement;
            XmlNode subNode = xmldoc.CreateNode(XmlNodeType.Element, "Link", "");
            XmlNode valueNode = xmldoc.CreateNode(XmlNodeType.Text, "linkValue", "");
            valueNode.Value = news.Url;
            subNode.AppendChild(valueNode);
            xe.AppendChild(subNode);
            rootnode.AppendChild(xe);
        }


        private string getBase64Pic(string picUrl, string refererUrl)
        {
            if (string.IsNullOrEmpty(picUrl))
                return "";
            WebClient wc = new WebClient();
            wc.Headers.Add(HttpRequestHeader.Referer, refererUrl);
            wc.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.CacheIfAvailable);
            try
            {
                byte[] data = wc.DownloadData(picUrl);
                if (data.Length > 0)
                    return Convert.ToBase64String(data);
                else
                    return "";
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }


        /// <summary>
        /// 显示新闻
        /// </summary>
        /// <param name="news"></param>
        private void showNews(List<News> news)
        {
            this.listView_News.Items.Clear();
            this.listView_News.Groups.Clear();
            this.listView_News.Sorting = SortOrder.None;
            ListViewGroup lvg = null;
            if (news != null)
            {
                ListViewItem lvi;
                this.listView_News.BeginUpdate();
                listView_News.ShowGroups = true;
                try
                {
                    foreach (News n in news)
                    {

                        lvg = new ListViewGroup(n.Title);
                        lvi = new ListViewItem(n.Title);
                        lvi.SubItems.Add(n.PubDate);
                        lvi.SubItems.Add(n.Media);
                        lvi.SubItems.Add("");
                        lvi.Tag = n;


                        this.listView_News.Items.Add(lvi);

                        if (MyTools.UploadHistory.InHistory(n.Url))
                        {
                            lvi.BackColor = Color.LightGreen;
                        }
                    }
                    this.listView_News.AutoResizeColumn(0, ColumnHeaderAutoResizeStyle.ColumnContent);


                }
                finally
                {
                    this.listView_News.EndUpdate();
                }
                this.ActiveControl = this.listView_News;
            }


        }


        /// <summary>
        /// 加载剪报属性控件
        /// </summary>
        private void LoadSharedPropertiesControl()
        {

            ClippingProperty cp;
            //cp = new ClippingProperty("标题", "headlineC");
            //this.tableLayoutPanel1.Controls.Add(cp, 0, 0);
            //cp.Dock = DockStyle.Fill;
            //_controllist.Add("标题", cp);

            //cp = new ClippingProperty("链接", "link");
            //cp = ClippingProperty.GetLinkClippingProperty("链接", "link");
            //this.tableLayoutPanel1.Controls.Add(cp, 0, 1);
            //cp.Dock = DockStyle.Fill;
            //_controllist.Add("链接", cp);


            //cp = new ClippingProperty("中文摘要", "synopsisC");
            //cp.Multiline = true;
            //this.tableLayoutPanel1.Controls.Add(cp, 0, 5);
            //cp.Dock = DockStyle.Fill;
            //cp.Height = 50;
            //_controllist.Add("中文摘要", cp);
            string[][] properties = new string[][] { new string[] { "媒体", "mediaID" }, new string[] { "版面", "Section" }, new string[] { "日期", "mediaDate" }, new string[] { "记者", "Reporter" }, new string[] { "字数", "Words" }, new string[] { "广告值", "adValue" }, new string[] { "页面", "Page" }, new string[] { "宽度", "Width" }, new string[] { "高度", "Height" }, new string[] { "页面大小", "pageSize" } };
            foreach (string[] s in properties)
            {
                cp = new ClippingProperty(s[0], s[1]);
                if (s[0] == "版面")
                    cp.Width = 405;
                else
                    cp.Width = 200;
                this.flowLayoutPanel_PublicFields.Controls.Add(cp);
                _controllist.Add(s[0], cp);
            }
            _controllist["广告值"].PropertyValue = Properties.Settings.Default.DefaultAd;
            _controllist["页面"].PropertyValue = Properties.Settings.Default.DefaultPage;
            _controllist["宽度"].PropertyValue = Properties.Settings.Default.DefaultWidth;
            _controllist["高度"].PropertyValue = Properties.Settings.Default.DefaultHeight;
            _controllist["页面大小"].PropertyValue = Properties.Settings.Default.DefaultPagesize;
        }

        private void TSB_SelectClass_Click(object sender, EventArgs e)
        {
            if (this._currentuser == null)
            {
                MessageBox.Show("尚未设置用户信息，无法取得分类列表！");
                return;
            }
            Dlg_SelectClient dlg = Dlg_SelectClient.GetDialog(this._currentuser.Clients);
            dlg.ClearSelectedCategory();
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                if (this._selectedclass != dlg.SelectedClass)
                {
                    this._selectedclass = dlg.SelectedClass;
                    List<string> s = new List<string>();
                    foreach (ClassInfo ci in _selectedclass)
                        s.Add(ci.FullPath);

                    this.TSB_SelectedClass.Text = string.Join("; ", s.ToArray());
                }
                if (this._selectedclient != dlg.SelectedClient)
                {
                    this._selectedclient = dlg.SelectedClient;

                    loadProfileControls();
                }
            }
        }
        /// <summary>
        /// 加载个性化字段控件
        /// </summary>
        private void loadProfileControls()
        {
            ClippingProperty oldp;
            foreach (Control c in flowLayoutPanel_ProfileFields.Controls)
            {
                oldp = c as ClippingProperty;
                if (oldp != null)
                {
                    if (this._controllist.ContainsKey(oldp.PropertyName))
                    {
                        this._controllist.Remove(oldp.PropertyName);
                    }
                }

            }
            foreach (Control c in flowLayoutPanel_MultiSelectProperty.Controls)
            {
                oldp = c as ClippingProperty;
                if (oldp != null)
                {
                    if (this._controllist.ContainsKey(oldp.PropertyName))
                    {
                        this._controllist.Remove(oldp.PropertyName);
                    }
                }

            }


            flowLayoutPanel_ProfileFields.Controls.Clear();
            flowLayoutPanel_MultiSelectProperty.Controls.Clear();

            foreach (Field f in this._selectedclient.Fields)
            {
                ClippingProperty cp = new ClippingProperty(f.Name, f.Name);
                cp.Width = 200;
                this.flowLayoutPanel_ProfileFields.Controls.Add(cp);
                this._controllist.Add(f.Name, cp);
            }
            foreach (Property p in this._selectedclient.Properties)
            {
                if (p.MultiSelect == false)
                {
                    ClippingProperty cp = new ClippingProperty(p.Name, p.Name, p.Options, false);
                    cp.Width = 200;
                    this.flowLayoutPanel_ProfileFields.Controls.Add(cp);
                    this._controllist.Add(p.Name, cp);
                }
                else
                {
                    ClippingProperty cp = new ClippingProperty(p.Name, p.Name, p.Options, true);


                    if (this.flowLayoutPanel_MultiSelectProperty.Width > 10)
                        cp.Width = this.flowLayoutPanel_MultiSelectProperty.Width - 10;

                    //int itemsPerRow = cp.Width / 106;
                    //int rowCount = p.Options.Count / itemsPerRow;
                    //if (p.Options.Count % itemsPerRow > 0)
                    //    rowCount += 1;
                    //cp.Height = 28*rowCount ;
                    cp.Height = cp.getDesiredHeight();

                    cp.SizeChanged -= new EventHandler(cp_SizeChanged);
                    cp.SizeChanged += new EventHandler(cp_SizeChanged);
                    this.flowLayoutPanel_MultiSelectProperty.Controls.Add(cp);
                    this._controllist.Add(p.Name, cp);

                }
            }
        }
        void cp_SizeChanged(object sender, EventArgs e)
        {
            int totalHeight = 0;
            foreach (Control control in this.flowLayoutPanel_MultiSelectProperty.Controls)
            {
                totalHeight += control.Height + 4;
            }
            if (this.flowLayoutPanel_MultiSelectProperty.Height < totalHeight)
                this.flowLayoutPanel_MultiSelectProperty.Height = totalHeight;
        }

        private void TSB_UploadClipping_Click(object sender, EventArgs e)
        {
            if (this._http == null)
            {
                MessageBox.Show("未指定上传剪报的HTTP，无法执行上传操作！");
                return;
            }
            if (this._selectedclass == null)
            {
                MessageBox.Show("未指定上传分类，无法执行上传操作！");
                return;
            }
            foreach (var news in this._news)
            {
                if (news.IsReady == false)
                {
                    MessageBox.Show("请等待全部新闻的正文下载完毕再执行上传操作。");
                    return;
                }
            }
            if (!check())
                return;
            Cursor = Cursors.WaitCursor;
            bool allSucceed = true;
            foreach (var news in this._news)
            {
                var result = uploadClipping(news);
                allSucceed = allSucceed & result;
            }
            Cursor = Cursors.Default;
            if (allSucceed)
            {
                if (MessageBox.Show("剪报上传成功，是否关闭窗体？", "上传成功", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    this.Close();
                }
            }
            else
            {
                MessageBox.Show("部分剪报上传失败。");
            }
        }
        private bool check()
        {
            foreach (Property p in this._selectedclient.Properties)
            {
                if (string.IsNullOrEmpty(_controllist[p.Name].PropertyValue))
                {
                    MessageBox.Show(string.Format("{0} 不能为空！", p.Name));
                    _controllist[p.Name].Focus();
                    return false;
                }

            }
            return true;
        }
        private bool uploadClipping(News news)
        {
            XmlDataDocument clippingxml = GenerateClipping(news);
            try
            {

                WebClient wc = new WebClient();
                string url = news.Url;
              
                wc.Credentials = _http.Credential;

				string tmpFileName = string.Format("{0}{1}.xml", DateTime.Now.ToString("yyyyMMddhhmmss"), MyTools.Hash.md5Hash(url).Replace("-", ""));
				string tmpFileFullPath = Path.Combine(Application.StartupPath, tmpFileName);
				File.WriteAllText(tmpFileFullPath, clippingxml.InnerXml, _xmlFileEncoding);

				if (!string.IsNullOrEmpty(_http.XmlSavePath))
				{
					string remoteFileFullPath = Path.Combine(_http.XmlSavePath, tmpFileName);
					File.Copy(tmpFileFullPath, remoteFileFullPath);
				}
				if (!string.IsNullOrEmpty(_http.HttpAddress))
				{
					string uploadurl = string.Format("{0}?user={1}&pwd={2}", _http.HttpAddress.Trim('/'), _http.User, _http.Password);
					wc.UploadFile(uploadurl, tmpFileFullPath);
					MyTools.UploadHistory.AddHistory(url);
					foreach (ListViewItem lvi in this.listView_News.Items)
					{
						if (lvi.Tag == news)
						{
							lvi.SubItems[lvi.SubItems.Count - 1].Text = "已上传";
							break;
						}
					}
				}
				try
				{
					File.Delete(tmpFileFullPath);
				}
				catch (Exception ex) { }
                return true;

            }
            catch (Exception ex)
            {
                foreach (ListViewItem lvi in this.listView_News.Items)
                {
                    if (lvi.Tag == news)
                    {
                        lvi.SubItems[lvi.SubItems.Count - 1].Text = "上传失败";
                        break;
                    }
                }
                return false;
            }

        }

        public static void SetXmlFileEncoding(Encoding encoding)
        {
            if (_xmlFileEncoding.WebName != encoding.WebName)
            {
                _xmlFileEncoding = encoding;
                initXmlTemplate();
            }
        }
    }
}
